<?php

namespace common\services\wechat;

use Yii;
use common\extensions\BaseService;
use WeChatPay\Builder;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Formatter;

/**
 * Desc 微信支付
 * * */
class PaymentService extends BaseService {

    public $instance = null;

    /**
     * 初始化公众号
     * @param string $key
     * @return mixed|string
     */
    public function init() {
        // 构造一个 APIv3 客户端实例
        $this->instance = Builder::factory([
                    'mchid' => '', //商户号
                    'serial' => '', //商户API证书的「证书序列号
                    'privateKey' => '', //商户API私钥
                    'certs' => [
                        '' => '',
                    ],
        ]);
    }

    /**
     * JSAPI支付
     * @param array $params
     * @return mixed|string
     */
    public function jsapi($params) {
        try {
            $data = [
                'appid' => '', //公众号
                'mchid' => '',
                'description' => '',
                'out_trade_no' => $params['order_sn'],
                'notify_url' => '',
                'amount' => ['total' => intval($params['amount'] * 100)], //单位:分
                'payer' => ['openid' => $params['openid']]
            ];
            $resp = $this->instance->chain('v3/pay/transactions/jsapi')->post(['json' => $data]);
            if ($resp->getStatusCode() != 200) {
                throw new Exception('微信支付错误');
            }
            //客户端唤起参数
            $params_pay = [
                'appId' => '',
                'timeStamp' => (string) Formatter::timestamp(),
                'nonceStr' => Formatter::nonce(),
                'package' => 'prepay_id=' . json_decode($resp->getBody(), true)['prepay_id'],
            ];
            $params_pay += ['paySign' => Rsa::sign(Formatter::joinedByLineFeed(...array_values($params_pay)), '商户API私钥'), 'signType' => 'RSA'];
            return self::returnSuccess($params_pay);
        } catch (\Exception $exc) {
            return self::returnError($exc->getMessage());
        }
    }

    /**
     * 支付回调
     * @param array $input
     */
    public function notify($input, $header) {
        try {
            $platform_public_key_instance = Rsa::from('file:///path/to/wechatpay/inWechatpaySerial.pem', Rsa::KEY_TYPE_PUBLIC);
            if (empty($platform_public_key_instance)) {
                throw new \Exception('证书异常');
            }
            if (abs(Formatter::timestamp() - (int) $header['wechatpay-timestamp']) >= 60 * 5) {
                throw new \Exception('已超过5分钟');
            }
            $verify = Rsa::verify(Formatter::joinedByLineFeed($header['wechatpay-timestamp'], $header['wechatpay-nonce'], $input), $header['wechatpay-signature'], $platform_public_key_instance);
            if (empty($verify)) {
                throw new \Exception('签名异常');
            }
            $params = json_decode($input, true);
            $result = json_decode(AesGcm::decrypt($params['ciphertext'], 'API3KEY', $params['nonce'], $params['associated_data']), true);
            if ($result['trade_state'] !== 'SUCCESS') {
                throw new \Exception('回调异常');
            }
        } catch (Exception $exc) {
            echo $exc->getTraceAsString();
        }
    }

}
